|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.Shared.Collections;
internal partial class MutableIntervalTree<T>
{
internal sealed class Node
{
internal T Value { get; }
internal Node? Left { get; private set; }
internal Node? Right { get; private set; }
internal int Height { get; private set; }
internal Node MaxEndNode { get; private set; }
internal Node(T value)
{
this.Value = value;
this.Height = 1;
this.MaxEndNode = this;
}
internal void SetLeftRight<TIntrospector>(Node? left, Node? right, in TIntrospector introspector)
where TIntrospector : struct, IIntervalIntrospector<T>
{
this.Left = left;
this.Right = right;
this.Height = 1 + Math.Max(Height(left), Height(right));
// We now must store the node that produces the maximum end. Since we might have tracking spans (or
// something similar) defining our values of "end", we can't store the int itself.
var thisEndValue = GetEnd(this.Value, in introspector);
var leftEndValue = MaxEndValue(left, in introspector);
var rightEndValue = MaxEndValue(right, in introspector);
if (thisEndValue >= leftEndValue && thisEndValue >= rightEndValue)
{
MaxEndNode = this;
}
else if ((leftEndValue >= rightEndValue) && left != null)
{
MaxEndNode = left.MaxEndNode;
}
else if (right != null)
{
MaxEndNode = right.MaxEndNode;
}
else
{
throw ExceptionUtilities.Unreachable();
}
}
// Sample:
// 1 2
// / \ / \
// 2 d 3 1
// / \ => / \ / \
// 3 c a b c d
// / \
// a b
internal Node RightRotation<TIntrospector>(in TIntrospector introspector)
where TIntrospector : struct, IIntervalIntrospector<T>
{
RoslynDebug.AssertNotNull(Left);
var oldLeft = this.Left;
this.SetLeftRight(this.Left.Right, this.Right, in introspector);
oldLeft.SetLeftRight(oldLeft.Left, this, in introspector);
return oldLeft;
}
// Sample:
// 1 2
// / \ / \
// a 2 1 3
// / \ => / \ / \
// b 3 a b c d
// / \
// c d
internal Node LeftRotation<TIntrospector>(in TIntrospector introspector)
where TIntrospector : struct, IIntervalIntrospector<T>
{
RoslynDebug.AssertNotNull(Right);
var oldRight = this.Right;
this.SetLeftRight(this.Left, this.Right.Left, in introspector);
oldRight.SetLeftRight(this, oldRight.Right, in introspector);
return oldRight;
}
// Sample:
// 1 1 3
// / \ / \ / \
// a 2 a 3 1 2
// / \ => / \ => / \ / \
// 3 d b 2 a b c d
// / \ / \
// b c c d
internal Node InnerRightOuterLeftRotation<TIntrospector>(in TIntrospector introspector)
where TIntrospector : struct, IIntervalIntrospector<T>
{
RoslynDebug.AssertNotNull(Right);
RoslynDebug.AssertNotNull(Right.Left);
var newTop = this.Right.Left;
var oldRight = this.Right;
this.SetLeftRight(this.Left, this.Right.Left.Left, in introspector);
oldRight.SetLeftRight(oldRight.Left.Right, oldRight.Right, in introspector);
newTop.SetLeftRight(this, oldRight, in introspector);
return newTop;
}
// Sample:
// 1 1 3
// / \ / \ / \
// 2 d 3 d 2 1
// / \ => / \ => / \ / \
// a 3 2 c a b c d
// / \ / \
// b c a b
internal Node InnerLeftOuterRightRotation<TIntrospector>(in TIntrospector introspector)
where TIntrospector : struct, IIntervalIntrospector<T>
{
RoslynDebug.AssertNotNull(Left);
RoslynDebug.AssertNotNull(Left.Right);
var newTop = this.Left.Right;
var oldLeft = this.Left;
this.SetLeftRight(this.Left.Right.Right, this.Right, in introspector);
oldLeft.SetLeftRight(oldLeft.Left, oldLeft.Right.Left, in introspector);
newTop.SetLeftRight(oldLeft, this, in introspector);
return newTop;
}
}
}
|